package com.shiroha.video.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.shiroha.common.exception.BadRequestException;
import com.shiroha.common.feign.client.NotificationClient;
import com.shiroha.video.enums.WorkType;
import com.shiroha.video.mapper.WorkMapper;
import com.shiroha.video.pojo.Work;
import com.shiroha.video.pojo.dto.WorkDTO;
import com.shiroha.video.pojo.dto.WorkImageDTO;
import com.shiroha.video.pojo.dto.WorkMetaData;
import com.shiroha.video.pojo.vo.WorkVO;
import com.shiroha.video.service.IWorkImageService;
import com.shiroha.video.service.IWorkService;
import com.shiroha.video.service.IJellyfinService;
import jakarta.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class WorkServiceImpl extends ServiceImpl<WorkMapper, Work> implements IWorkService {

    private final AsyncService asyncService;
    private final IWorkImageService workImageService;
    private final IJellyfinService jellyfinService;
    private final NotificationClient notificationClient;

    /**
     * 分页查询作品
     * @param pageNum 页数
     * @param pageSize 页面大小
     * @param userId 用户ID，游客登陆时为 null
     * @return 分页信息
     */
    @Override
    public Page<WorkVO> selectWorksByPage(int pageNum, int pageSize, @Nullable UUID userId) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        return this.mapper.xmlPaginate("selectPage", Page.of(pageNum, pageSize), params);
    }

    /**
     * 上传作品
     *
     * @param workDTO 作品及作者信息
     */
    @Override
    @Transactional
    public void uploadWork(WorkDTO workDTO) {
        switch (workDTO.getType()) {
            case VIDEO -> saveVideo(workDTO);
            case PICTURE -> saveImage(workDTO);
        }
    }

    @Transactional
    protected void saveVideo(WorkDTO workDTO) throws BadRequestException {
        try {
            // 首先保存work
            Work work = saveWork(workDTO);
            WorkMetaData workMetaData = toWorkMetaDataDTO(workDTO);
            // 上传到 media 目录
            jellyfinService.uploadVideo(workMetaData, workDTO.getFiles()[0]);
            // 延迟获取播放URL和封面URL，然后更新work表
            asyncService.delayedUpdate(work, workMetaData);
        } catch (Exception e) {
            log.error("上传失败，{}", workDTO.getTitle(), e);
            throw new BadRequestException(e.getMessage());
        }
    }

    /**
     * 保存作品图集
     *
     * @param workDTO 包含作品信息的 DTO 对象
     * @return 保存后的 Work 实体
     * @throws BadRequestException 如果上传失败，则抛出此异常
     */
    @Transactional
    protected void saveImage(WorkDTO workDTO) throws BadRequestException {
        try {
            Work work = saveWork(workDTO);
            WorkMetaData workMetaData = toWorkMetaDataDTO(workDTO);

            Optional<String> coverUrlOpt = workImageService.saveWorkImages(workMetaData);
            coverUrlOpt.ifPresent(coverUrl -> {
                work.setPlayUrl(getWorkImagesUrl(work.getId()));
                work.setCoverUrl(coverUrl);
                this.updateById(work);
            });
        } catch (Exception e) {
            log.error("上传失败，{}", workDTO.getTitle(), e);
            throw new BadRequestException(e.getMessage());
        }
    }

    /**
     * 初次保存 work，并返回 workId
     * @param workDTO DTO对象
     * @return 保存后的 work
     */
    @Transactional
    protected Work saveWork(WorkDTO workDTO) {
        Work work = new Work();
        work.setAuthorId(workDTO.getAuthorId());
        work.setType(workDTO.getType());
        work.setTitle(workDTO.getTitle());

        // 保存到数据库
        this.save(work);
        workDTO.setId(work.getId());

        // 保存作品标签
        if(workDTO.getTags().length >= 1) {
            saveWorkTags(workDTO);
        }
        return work;
    }

    // 保存work tags
    @Transactional
    protected void saveWorkTags(WorkDTO workDTO) {
        this.getMapper().insertWorkTags(workDTO.getId(), workDTO.getTags());
    }

    private WorkImageDTO toWorkImageDTO(MultipartFile file) {
        return WorkImageDTO.create()
                .setFile(file)
                .setDescription(null);
    }

    private WorkMetaData toWorkMetaDataDTO(WorkDTO workDTO) {
        WorkMetaData workMetaData = WorkMetaData.create()
                .setWorkId(workDTO.getId())
                .setAuthorId(workDTO.getAuthorId())
                .setDescription(workDTO.getTitle());

        if(workDTO.getType() == WorkType.PICTURE) {
            List<WorkImageDTO> workImageDTOS = Arrays.stream(workDTO.getFiles())
                    .map(this::toWorkImageDTO)
                    .map(workImageDTO -> workImageDTO.setWorkId(workDTO.getId()))
                    .toList();
            workMetaData.setWorkImageDTOList(workImageDTOS);
        }
        return workMetaData;
    }

    private String getWorkImagesUrl(Long workId) {
        return "/vs/works/" + workId + "/images";
    }
}
